Some Useful Monitors

monitors

In this section we describe some of the specific monitors that are built into the p4 library. Each of them has its own pre-defined type, which can be used to allocate storage for them, which should be in shared memory. See the p4/monitors directory for examples. A lock is itself a monitor, with no extra delay queues.

p4_lock_init
\begin{example}
VOID p4_lock_init(l)
p4_lock_t *l;
\end{example}
initializes the lock l. Must be used prior to any attempts to lock or unlock l.

lock p4_lock
\begin{example}
VOID p4_lock(l)
p4_lock_t *l;
\end{example}
blocks if the lock l is already locked, otherwise locks l and proceeds.

unlock p4_unlock
\begin{example}
VOID p4_unlock(l)
p4_lock_t *l;
\end{example}
unlocks the lock l.

p4_getsub
\begin{example}
VOID p4_getsub(gs,s,max,nprocs)
p4_getsub_monitor_t *gs;
int *s,max,nprocs;
\end{example}
is a procedure used to obtain the next value of a shared counter (subscript). It takes as its first argument, a pointer to a getsub monitor that protects the shared counter. It assigns the current value of the counter to the integer that s points to, and then increments the counter by 1. p4_getsub_init initially sets the counter to 0. When the counter passes the value max, all nprocs processes are returned the value (-1) once, then the counter is reset to 0 for further use.

p4_getsubs
\begin{example}
VOID p4_getsubs(gs,s,max,nprocs,stride)
p4_getsub_monitor_t *gs;
int *s,max,nprocs,stride;
\end{example}
is like p4_getsub except that the counter is increased on each call by stride instead of 1.

p4_getsub_init
\begin{example}
int p4_getsub_init(gs)
p4_getsub_monitor_t *gs;
\end{example}
initializes the getsub monitor pointed to by gs; this initialization includes assigning a value of 0 to the counter that the monitor protects.

The standard barrier synchronization pattern is expressed as a monitor. There can be multiple barrier monitors, and one can wait for only some of the processes at the barrier if this is desired.

barrier p4_barrier
\begin{example}
VOID p4_barrier(b,nprocs)
p4_barrier_monitor_t *b;
int nprocs;
\end{example}
causes the executing process to hang until nprocs processes execute a barrier instruction with a pointer to the same barrier monitor b as an argument.

p4_barrier_init
\begin{example}
int p4_barrier_init(b)
p4_barrier_monitor_t *b;
\end{example}
initializes the barrier monitor b; this procedure should be invoked before you attempt to use the monitor in any operations.

Finally, the askfor monitor functions like a general dispatcher of work.

askfor monitor p4_askfor
\begin{example}
int p4_askfor(af,nprocs,getprob_fxn,problem,reset_fxn)
p4_askfor...
...t nprocs;
int (*getprob_fxn)();
VOID *problem;
int (*reset_fxn)();
\end{example}
requests a new ``problem'' to work on from the problem pool. The arguments are (1) a pointer to the askfor monitor that protects the problem pool, (2) the number of processes that call this procedure (with af) looking for work, (3) a pointer to the user-written procedure that obtains a problem from the pool, (4) a pointer that is filled in with the address of a user-defined representation of a problem to be solved, and (5) a pointer to a user-written procedure to reset when all problems in the pool are solved, in case the same monitor is re-used for another set of problems later. p4_askfor returns an integer indicating whether a problem was successfully obtained or not:


\begin{example}
-1 : program is terminating (some process called p4_progend)
0...
...> 1 : a process found a solution and called p4_probend with code n
\end{example}
For a detailed discussion of the ``askfor'' monitor, see [#!lusk-overbeek:p4-book!#].

p4_update
\begin{example}
int p4_update(af,putprob_fxn,problem)
p4_askfor_monitor_t *af;
int (*putprob_fxn)();
VOID *problem;
\end{example}
updates the problem pool being managed by the askfor monitor. The arguments are (1) a pointer to the askfor monitor that protects the problem pool, (2) a pointer to the user-written procedure that puts problems into the pool, and (3) a pointer to a user-defined representation of a problem to be put in the pool. Putprob_fxn should return 1 if it did indeed put a new problem into the pool, so that any delayed processes should wake up and re-examine the pool (this logic is handled by the p4_askfor) and 0 if upon entering the monitor and examining its potential problem together with the data there it decided not to add a new problem to the pool. It can be assumed that the ``putprob'' logic (defined by putprob_fxn) is executed inside the monitor.

p4_askfor_init
\begin{example}
int p4_askfor_init(af)
p4_askfor_monitor_t *af;
\end{example}
initializes the askfor monitor af; this procedure should be invoked before you attempt to use the monitor in any operations.

p4_probend
\begin{example}
VOID p4_probend(af,code)
p4_askfor_monitor_t *af;
int code;
\end{example}
allows the user process to mark a problem as solved early when several processes are coordinating their activities via an askfor monitor. The code is an integer value that will be returned to all processes when they ``askfor'' a new sub-problem to work on.

p4_progend
\begin{example}
VOID p4_progend(af)
p4_askfor_monitor_t *af;
\end{example}
allows a process to cause a return code of (-1) to be returned to all processes using an askfor monitor. This would typically be called by a master process to indicate that no more problems are to be solved and that all slave processes should terminate.

Functions for Timing p4 Programs,Functions for Debugging p4 Programs,Functions for Shared Memory,Top